package com.nolon.flange

import android.content.Context
import android.content.res.Resources
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.nolon.flange.dao.*
import com.nolon.flange.model.Order
import com.nolon.flange.model.Part
import com.nolon.flange.model.Project
import com.nolon.flange.model.RawInfo
import com.nolon.flange.model.RawSolution
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

@Database(
    entities = [Project::class, Order::class, Part::class, RawInfo::class, RawSolution::class],
    version = 1
)
abstract class AppDatabase : RoomDatabase() {
    abstract val projectDao: ProjectDao
    abstract val orderDao: OrderDao
    abstract val partDao: PartDao
    abstract val rawInfoDao: RawInfoDao
    abstract val rawSolutionDao: RawSolutionDao

    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            synchronized(this) {
                var instance = INSTANCE
                if (instance == null) {

                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        AppDatabase::class.java,
                        "project_database"
                    )
                        // Wipes and rebuilds instead of migrating if no Migration object.
                        // Migration is not part of this lesson. You can learn more about
                        // migration with Room in this blog post:
                        // https://medium.com/androiddevelopers/understanding-migrations-with-room-f01e04b07929
//                        .addCallback(AppDatabaseCallback())
                        .fallbackToDestructiveMigration()
                        .build()
                    INSTANCE = instance
                }
                return instance
            }
        }
    }

    private class AppDatabaseCallback(
        private val scope: CoroutineScope,
        private val resources: Resources
    ) : RoomDatabase.Callback() {

        override fun onCreate(db: SupportSQLiteDatabase) {
            super.onCreate(db)
            INSTANCE?.let { database ->
                scope.launch {
                    val projectDao = database.projectDao
                    prePopulateDatabase(projectDao)
                }
            }
        }

        private suspend fun prePopulateDatabase(projectDao: ProjectDao) {
            val jsonString = resources.openRawResource(R.raw.project_list).bufferedReader().use {
                it.readText()
            }
            val typeToken = object : TypeToken<List<Project>>() {}.type
            val projects = Gson().fromJson<List<Project>>(jsonString, typeToken)
            projectDao.insertAll(projects)
        }
    }
}